<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>JavaScript待办事项应用</title>
  <style>
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    body {
      font-family: 'Arial', sans-serif;
      line-height: 1.6;
      color: #333;
      background-color: #f5f5f5;
      padding: 20px;
    }
    
    .container {
      max-width: 600px;
      margin: 0 auto;
      background-color: #fff;
      border-radius: 5px;
      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
      padding: 20px;
    }
    
    h1 {
      text-align: center;
      margin-bottom: 20px;
      color: #2c3e50;
    }
    
    .todo-form {
      display: flex;
      margin-bottom: 20px;
    }
    
    .todo-input {
      flex: 1;
      padding: 10px;
      border: 1px solid #ddd;
      border-radius: 4px 0 0 4px;
      font-size: 16px;
    }
    
    .todo-submit {
      padding: 10px 15px;
      background-color: #42b983;
      color: white;
      border: none;
      border-radius: 0 4px 4px 0;
      cursor: pointer;
      font-size: 16px;
    }
    
    .todo-submit:hover {
      background-color: #3aa876;
    }
    
    .todo-list {
      list-style: none;
    }
    
    .todo-item {
      display: flex;
      align-items: center;
      padding: 10px;
      border-bottom: 1px solid #eee;
    }
    
    .todo-item:last-child {
      border-bottom: none;
    }
    
    .todo-checkbox {
      margin-right: 10px;
      width: 20px;
      height: 20px;
    }
    
    .todo-text {
      flex: 1;
      font-size: 16px;
    }
    
    .todo-text.completed {
      text-decoration: line-through;
      color: #888;
    }
    
    .todo-delete {
      padding: 5px 10px;
      background-color: #e74c3c;
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }
    
    .todo-delete:hover {
      background-color: #c0392b;
    }
    
    .filters {
      display: flex;
      justify-content: center;
      margin-top: 20px;
      gap: 10px;
    }
    
    .filter-btn {
      padding: 5px 10px;
      background-color: #f1f1f1;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }
    
    .filter-btn.active {
      background-color: #42b983;
      color: white;
    }
    
    .todo-stats {
      text-align: center;
      margin-top: 15px;
      font-size: 14px;
      color: #666;
    }
    
    .design-patterns {
      margin-top: 30px;
      padding-top: 20px;
      border-top: 1px dashed #ddd;
    }
    
    .pattern-info {
      background-color: #f8f9fa;
      border-left: 4px solid #42b983;
      padding: 15px;
      margin-bottom: 20px;
      border-radius: 0 4px 4px 0;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>待办事项应用</h1>
    
    <form class="todo-form" id="todo-form">
      <input type="text" class="todo-input" id="todo-input" placeholder="添加新的待办事项..." required>
      <button type="submit" class="todo-submit">添加</button>
    </form>
    
    <ul class="todo-list" id="todo-list"></ul>
    
    <div class="filters">
      <button class="filter-btn active" data-filter="all">全部</button>
      <button class="filter-btn" data-filter="active">未完成</button>
      <button class="filter-btn" data-filter="completed">已完成</button>
    </div>
    
    <div class="todo-stats" id="todo-stats"></div>
    
    <div class="design-patterns">
      <h2>应用中的设计模式</h2>
      
      <div class="pattern-info">
        <h3>模块模式 (Module Pattern)</h3>
        <p>整个应用使用立即执行函数表达式(IIFE)创建一个模块，实现私有变量和方法的封装。</p>
      </div>
      
      <div class="pattern-info">
        <h3>观察者模式 (Observer Pattern)</h3>
        <p>当待办事项数据变化时，自动更新UI，实现了数据和视图的解耦。</p>
      </div>
      
      <div class="pattern-info">
        <h3>命令模式 (Command Pattern)</h3>
        <p>每个用户操作（添加、删除、切换状态）被封装成独立的函数。</p>
      </div>
    </div>
  </div>

  <script>
    // 使用立即执行函数表达式(IIFE)创建模块 - 模块模式
    const TodoApp = (function() {
      // 私有变量
      const todos = JSON.parse(localStorage.getItem('todos')) || [];
      let currentFilter = 'all';
      
      // DOM元素
      const todoForm = document.getElementById('todo-form');
      const todoInput = document.getElementById('todo-input');
      const todoList = document.getElementById('todo-list');
      const filterButtons = document.querySelectorAll('.filter-btn');
      const todoStats = document.getElementById('todo-stats');
      
      // 私有方法：保存到本地存储
      function saveTodos() {
        localStorage.setItem('todos', JSON.stringify(todos));
      }
      
      // 私有方法：创建待办事项元素
      function createTodoElement(todo) {
        const li = document.createElement('li');
        li.className = 'todo-item';
        li.dataset.id = todo.id;
        
        const checkbox = document.createElement('input');
        checkbox.type = 'checkbox';
        checkbox.className = 'todo-checkbox';
        checkbox.checked = todo.completed;
        
        const span = document.createElement('span');
        span.className = `todo-text ${todo.completed ? 'completed' : ''}`;
        span.textContent = todo.text;
        
        const deleteButton = document.createElement('button');
        deleteButton.className = 'todo-delete';
        deleteButton.textContent = '删除';
        
        li.appendChild(checkbox);
        li.appendChild(span);
        li.appendChild(deleteButton);
        
        return li;
      }
      
      // 私有方法：渲染待办事项列表 - 观察者模式的一部分
      function renderTodos() {
        todoList.innerHTML = '';
        
        const filteredTodos = todos.filter(todo => {
          if (currentFilter === 'active') return !todo.completed;
          if (currentFilter === 'completed') return todo.completed;
          return true; // 'all' filter
        });
        
        filteredTodos.forEach(todo => {
          const todoElement = createTodoElement(todo);
          todoList.appendChild(todoElement);
        });
        
        updateStats();
      }
      
      // 私有方法：更新统计信息
      function updateStats() {
        const total = todos.length;
        const completed = todos.filter(todo => todo.completed).length;
        const active = total - completed;
        
        todoStats.textContent = `总计: ${total} | 已完成: ${completed} | 未完成: ${active}`;
      }
      
      // 私有方法：添加新待办事项 - 命令模式
      function addTodo(text) {
        const newTodo = {
          id: Date.now().toString(),
          text,
          completed: false,
          createdAt: new Date()
        };
        
        todos.push(newTodo);
        saveTodos();
        renderTodos();
      }
      
      // 私有方法：删除待办事项 - 命令模式
      function deleteTodo(id) {
        const index = todos.findIndex(todo => todo.id === id);
        if (index !== -1) {
          todos.splice(index, 1);
          saveTodos();
          renderTodos();
        }
      }
      
      // 私有方法：切换待办事项状态 - 命令模式
      function toggleTodo(id) {
        const todo = todos.find(todo => todo.id === id);
        if (todo) {
          todo.completed = !todo.completed;
          saveTodos();
          renderTodos();
        }
      }
      
      // 私有方法：设置过滤器
      function setFilter(filter) {
        currentFilter = filter;
        
        // 更新按钮状态
        filterButtons.forEach(button => {
          if (button.dataset.filter === filter) {
            button.classList.add('active');
          } else {
            button.classList.remove('active');
          }
        });
        
        renderTodos();
      }
      
      // 初始化函数
      function init() {
        // 表单提交事件
        todoForm.addEventListener('submit', function(event) {
          event.preventDefault();
          const text = todoInput.value.trim();
          
          if (text) {
            addTodo(text);
            todoInput.value = '';
          }
        });
        
        // 待办事项列表点击事件（事件委托）
        todoList.addEventListener('click', function(event) {
          const todoItem = event.target.closest('.todo-item');
          if (!todoItem) return;
          
          const id = todoItem.dataset.id;
          
          if (event.target.classList.contains('todo-checkbox')) {
            toggleTodo(id);
          } else if (event.target.classList.contains('todo-delete')) {
            deleteTodo(id);
          }
        });
        
        // 过滤器点击事件
        document.querySelector('.filters').addEventListener('click', function(event) {
          if (event.target.classList.contains('filter-btn')) {
            const filter = event.target.dataset.filter;
            setFilter(filter);
          }
        });
        
        // 初始渲染
        renderTodos();
      }
      
      // 公共接口
      return {
        init: init
      };
    })();
    
    // 初始化应用
    TodoApp.init();
  </script>
</body>
</html>